#ifndef _MESSAGE_FACTORY_H_
#define _MESSAGE_FACTORY_H_

#include <map>

#include <google/protobuf/message_lite.h>

typedef unsigned short TMessageID;

class IMessageCreator
{
public:
    virtual ~IMessageCreator(){}
    virtual google::protobuf::MessageLite* create() = 0;
};

class MessageFactory
{
private:
    template <typename T>
    class MessageCreator : public IMessageCreator
    {
    public:
        MessageCreator(TMessageID msgid)
        : msgTypeID_(msgid)
        {
            
        }
        
    public:
        virtual google::protobuf::MessageLite* create()
        {
            return new T();
        }
        
        T* downCast(google::protobuf::MessageLite* msg)
        {
            return static_cast<T*>(msg);
        }
        
        TMessageID getMessageID() const
        {
            return msgTypeID_;
        }
        
    private:
        TMessageID msgTypeID_;
    };
    
public:
    MessageFactory();
    ~MessageFactory();
    
    static void Initalize()
    {
        GOOGLE_PROTOBUF_VERIFY_VERSION;
    }

    static void Destroy()
    {
        if (NULL != pFactory_)
        {
            pFactory_->clearAllMessage();
            
            delete pFactory_;
            pFactory_ = NULL;
        }
        
        google::protobuf::ShutdownProtobufLibrary();
    }
    
    static MessageFactory* GetInstancePtr()
    {
        if (NULL == pFactory_)
        {
            pFactory_ = new MessageFactory();
        }
        
        assert(pFactory_ != NULL);
        return pFactory_;
    }
    
public:
    template <typename T>
    void InstallMessage(TMessageID msgID)
    {
        MessageCreator<T>* pCreator = new MessageCreator<T>(msgID);
        messageCreatorMap_.insert(std::pair<TMessageID, IMessageCreator*>(msgID, pCreator));
    }

    google::protobuf::MessageLite* createMessageByID(TMessageID msgID);
    
    void clearAllMessage();

private:
    std::map<TMessageID, IMessageCreator*> messageCreatorMap_;
    
    static MessageFactory* pFactory_;
};

#define INSTALL_MESSAGE(ID, MTYPE) MessageFactory::GetInstancePtr()->InstallMessage<MTYPE>(ID)
#define CREATEMSG(ID) MessageFactory::GetInstancePtr()->createMessageByID(ID)

#endif // _MESSAGE_FACTORY_H_
